package com.mega.ycy;

import com.google.common.collect.Lists;
import com.mega.ycy.mixin.PlayerListAccessor;
import com.mojang.authlib.GameProfile;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.SPacketChangeGameState;
import net.minecraft.network.play.server.SPacketRespawn;
import net.minecraft.network.play.server.SPacketSetExperience;
import net.minecraft.network.play.server.SPacketSpawnPosition;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.management.DemoPlayerInteractionManager;
import net.minecraft.server.management.PlayerInteractionManager;
import net.minecraft.server.management.PlayerList;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;

import java.util.List;
import java.util.UUID;

public class SBPlayer {
    public static class MP extends EntityPlayerMP {

        public MP(MinecraftServer server, WorldServer worldIn, GameProfile profile, PlayerInteractionManager interactionManagerIn) {
            super(server, worldIn, profile, interactionManagerIn);
        }

        private boolean is() {
            return Yiciyuan_EVENT.isSafe(this);
        }

        @Override
        public float getHealth() {
            if (is())
                return 20F;
            if (Yiciyuan_EVENT.isDeath(this))
                return 0F;
            return super.getHealth();
        }

        @Override
        public float getMaxHealth() {
            if (is())
                return 20F;
            return super.getMaxHealth();
        }

        @Override
        public boolean isEntityAlive() {
            if (is())
                return true;
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.isEntityAlive();
        }

        @Override
        public void onRemovedFromWorld() {
            if (!is())
                super.onRemovedFromWorld();
        }

        @Override
        public void onKillCommand() {
            if (!is())
                super.onKillCommand();
        }

        @Override
        public boolean attackEntityFrom(DamageSource source, float amount) {
            if (is())
                return false;
            return super.attackEntityFrom(source, amount);
        }

        @Override
        public NBTTagCompound getEntityData() {
            if (Yiciyuan_EVENT.isDeath(this))
                return new NBTTagCompound();
            return super.getEntityData();
        }

        @Override
        public boolean addTag(String tag) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.addTag(tag);
        }

        @Override
        public void writeEntityToNBT(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return;
            super.writeEntityToNBT(compound);
        }

        @Override
        public boolean writeToNBTOptional(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.writeToNBTOptional(compound);
        }

        @Override
        public boolean writeToNBTAtomically(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.writeToNBTAtomically(compound);
        }

        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return new NBTTagCompound();
            return super.writeToNBT(compound);
        }
    }

    public static class SP extends EntityPlayerSP {

        public SP(EntityPlayerSP sp) {
            super(Minecraft.getMinecraft(), sp.world, Minecraft.getMinecraft().player.connection, sp.getStatFileWriter(), sp.getRecipeBook());
        }
        private boolean is() {
            return Yiciyuan_EVENT.isSafe(this);
        }

        @Override
        public float getHealth() {
            if (is())
                return 20F;
            if (Yiciyuan_EVENT.isDeath(this))
                return 0F;
            return super.getHealth();
        }

        @Override
        public NBTTagCompound getEntityData() {
            if (Yiciyuan_EVENT.isDeath(this))
                return new NBTTagCompound();
            return super.getEntityData();
        }

        @Override
        public boolean addTag(String tag) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.addTag(tag);
        }

        @Override
        public void writeEntityToNBT(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return;
            super.writeEntityToNBT(compound);
        }

        @Override
        public boolean writeToNBTOptional(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.writeToNBTOptional(compound);
        }

        @Override
        public boolean writeToNBTAtomically(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.writeToNBTAtomically(compound);
        }

        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            if (Yiciyuan_EVENT.isDeath(this))
                return new NBTTagCompound();
            return super.writeToNBT(compound);
        }

        @Override
        public float getMaxHealth() {
            if (is())
                return 20F;
            return super.getMaxHealth();
        }

        @Override
        public boolean isEntityAlive() {
            if (is())
                return true;
            if (Yiciyuan_EVENT.isDeath(this))
                return false;
            return super.isEntityAlive();
        }

        @Override
        public void onRemovedFromWorld() {
            if (!is())
                super.onRemovedFromWorld();
        }

        @Override
        public void onKillCommand() {
            if (!is())
                super.onKillCommand();
        }

        @Override
        public boolean attackEntityFrom(DamageSource source, float amount) {
            if (is())
                return false;
            return super.attackEntityFrom(source, amount);
        }
    }

    public static class PL extends PlayerList {

        public PL(MinecraftServer server, PlayerList list) {
            super(server);
            uuidToPlayerMap = list.uuidToPlayerMap;
            ((PlayerListAccessor)this).set(list.getPlayers());
        }

        @Override
        public EntityPlayerMP recreatePlayerEntity(EntityPlayerMP playerIn, int dimension, boolean conqueredEnd)
        {
            World world = getServerInstance().getWorld(dimension);
            if (world == null)
            {
                dimension = playerIn.getSpawnDimension();
            }
            else if (!world.provider.canRespawnHere())
            {
                dimension = world.provider.getRespawnDimension(playerIn);
            }
            if (getServerInstance().getWorld(dimension) == null) dimension = 0;

            playerIn.getServerWorld().getEntityTracker().removePlayerFromTrackers(playerIn);
            playerIn.getServerWorld().getEntityTracker().untrack(playerIn);
            playerIn.getServerWorld().getPlayerChunkMap().removePlayer(playerIn);
            this.getPlayers().remove(playerIn);
            this.getServerInstance().getWorld(playerIn.dimension).removeEntityDangerously(playerIn);
            BlockPos blockpos = playerIn.getBedLocation(dimension);
            boolean flag = playerIn.isSpawnForced(dimension);
            playerIn.dimension = dimension;
            PlayerInteractionManager playerinteractionmanager;

            if (this.getServerInstance().isDemo())
            {
                playerinteractionmanager = new DemoPlayerInteractionManager(this.getServerInstance().getWorld(playerIn.dimension));
            }
            else
            {
                playerinteractionmanager = new PlayerInteractionManager(this.getServerInstance().getWorld(playerIn.dimension));
            }

            SBPlayer.MP entityplayermp = new SBPlayer.MP(this.getServerInstance(), this.getServerInstance().getWorld(playerIn.dimension), playerIn.getGameProfile(), playerinteractionmanager);
            entityplayermp.connection = playerIn.connection;
            entityplayermp.copyFrom(playerIn, conqueredEnd);
            entityplayermp.dimension = dimension;
            entityplayermp.setEntityId(playerIn.getEntityId());
            entityplayermp.setCommandStats(playerIn);
            entityplayermp.setPrimaryHand(playerIn.getPrimaryHand());

            for (String s : playerIn.getTags())
            {
                entityplayermp.addTag(s);
            }

            WorldServer worldserver = this.getServerInstance().getWorld(playerIn.dimension);
            this.setPlayerGameTypeBasedOnOther(entityplayermp, playerIn, worldserver);

            if (blockpos != null)
            {
                BlockPos blockpos1 = EntityPlayer.getBedSpawnLocation(this.getServerInstance().getWorld(playerIn.dimension), blockpos, flag);

                if (blockpos1 != null)
                {
                    entityplayermp.setLocationAndAngles((double)((float)blockpos1.getX() + 0.5F), (double)((float)blockpos1.getY() + 0.1F), (double)((float)blockpos1.getZ() + 0.5F), 0.0F, 0.0F);
                    entityplayermp.setSpawnPoint(blockpos, flag);
                }
                else
                {
                    entityplayermp.connection.sendPacket(new SPacketChangeGameState(0, 0.0F));
                }
            }

            worldserver.getChunkProvider().provideChunk((int)entityplayermp.posX >> 4, (int)entityplayermp.posZ >> 4);

            while (!worldserver.getCollisionBoxes(entityplayermp, entityplayermp.getEntityBoundingBox()).isEmpty() && entityplayermp.posY < 256.0D)
            {
                entityplayermp.setPosition(entityplayermp.posX, entityplayermp.posY + 1.0D, entityplayermp.posZ);
            }

            entityplayermp.connection.sendPacket(new SPacketRespawn(entityplayermp.dimension, entityplayermp.world.getDifficulty(), entityplayermp.world.getWorldInfo().getTerrainType(), entityplayermp.interactionManager.getGameType()));
            BlockPos blockpos2 = worldserver.getSpawnPoint();
            entityplayermp.connection.setPlayerLocation(entityplayermp.posX, entityplayermp.posY, entityplayermp.posZ, entityplayermp.rotationYaw, entityplayermp.rotationPitch);
            entityplayermp.connection.sendPacket(new SPacketSpawnPosition(blockpos2));
            entityplayermp.connection.sendPacket(new SPacketSetExperience(entityplayermp.experience, entityplayermp.experienceTotal, entityplayermp.experienceLevel));
            this.updateTimeAndWeatherForPlayer(entityplayermp, worldserver);
            this.updatePermissionLevel(entityplayermp);
            worldserver.getPlayerChunkMap().addPlayer(entityplayermp);
            worldserver.spawnEntity(entityplayermp);
            this.getPlayers().add(entityplayermp);
            this.uuidToPlayerMap.put(entityplayermp.getUniqueID(), entityplayermp);
            entityplayermp.addSelfToInternalCraftingInventory();
            entityplayermp.setHealth(entityplayermp.getHealth());
            net.minecraftforge.fml.common.FMLCommonHandler.instance().firePlayerRespawnEvent(entityplayermp, conqueredEnd);
            return entityplayermp;
        }

        private void setPlayerGameTypeBasedOnOther(EntityPlayerMP target, EntityPlayerMP source, World worldIn)
        {
            if (source != null)
            {
                target.interactionManager.setGameType(source.interactionManager.getGameType());
            }
            else if (this.gameType != null)
            {
                target.interactionManager.setGameType(this.gameType);
            }

            target.interactionManager.initializeGameType(worldIn.getWorldInfo().getGameType());
        }

        @Override
        public EntityPlayerMP createPlayerForUser(GameProfile profile)
        {
            UUID uuid = EntityPlayer.getUUID(profile);
            List<EntityPlayerMP> list = Lists.<EntityPlayerMP>newArrayList();

            for (int i = 0; i < this.getPlayers().size(); ++i)
            {
                EntityPlayerMP entityplayermp = this.getPlayers().get(i);

                if (entityplayermp.getUniqueID().equals(uuid))
                {
                    list.add(entityplayermp);
                }
            }

            EntityPlayerMP entityplayermp2 = this.uuidToPlayerMap.get(profile.getId());

            if (entityplayermp2 != null && !list.contains(entityplayermp2))
            {
                list.add(entityplayermp2);
            }

            for (EntityPlayerMP entityplayermp1 : list)
            {
                entityplayermp1.connection.disconnect(new TextComponentTranslation("multiplayer.disconnect.duplicate_login", new Object[0]));
            }

            PlayerInteractionManager playerinteractionmanager;

            if (this.getServerInstance().isDemo())
            {
                playerinteractionmanager = new DemoPlayerInteractionManager(this.getServerInstance().getWorld(0));
            }
            else
            {
                playerinteractionmanager = new PlayerInteractionManager(this.getServerInstance().getWorld(0));
            }

            return new SBPlayer.MP(this.getServerInstance(), this.getServerInstance().getWorld(0), profile, playerinteractionmanager);
        }
    }
}
